package org.lab.mtga.core.parser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.inject.Inject;

import org.apache.commons.lang.StringUtils;
import org.lab.mtga.core.model.Card;
import org.lab.mtga.core.model.Deck;
import org.lab.mtga.core.services.CardRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MtgoParser implements DeckParser {

	private static final String PATTERN_CARD = "^(\\d+)\\s+(.+\\w)\\s*?$";
	private static final String PATTERN_SIDEBOARD = "^sideboard$";
	private static final String PATTERN_MODE = "^\\s*\\[mode=(.+)\\s*\\]$";
	private static final String PATTERN_MODE_OPTION = "^\\s*([\\+|\\-][\\d]+)\\s+(.+)$";
	private static final Logger LOG = LoggerFactory.getLogger(MtgoParser.class);

	@Inject
	private CardRepository cardRepository;

	@Override
	public Deck parse(InputStream inputStream) throws IOException {
		Deck deck = new Deck();
		deck.initialize();
		BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
		Pattern cardLinePattern = Pattern.compile(PATTERN_CARD);
		Pattern modePattern = Pattern.compile(PATTERN_MODE);
		Pattern sideboardPattern = Pattern.compile(PATTERN_SIDEBOARD);
		Pattern modeOptionPattern = Pattern.compile(PATTERN_MODE_OPTION);
		Boolean isSideboard = false;
		String mode = null;
		String line;
		while ((line = reader.readLine()) != null) {
			try {
				if (StringUtils.isEmpty(line)) {
					continue;
				} else if (sideboardPattern.matcher(line).matches()) {
					isSideboard = true;
				} else if (modePattern.matcher(line).matches()) {
					Matcher matcher = modePattern.matcher(line);
					matcher.matches();
					mode = matcher.group(1);
				} else if (mode != null && modeOptionPattern.matcher(line).matches()) {
					Matcher matcher = modeOptionPattern.matcher(line);
					matcher.matches();
					Integer count = Integer.parseInt(matcher.group(1));
					String name = matcher.group(2);
					Card card = cardRepository.findByName(name);
					deck.addCardToOptionGroup(mode, card, count);
				} else {
					Matcher matcherCardLinePattern = cardLinePattern.matcher(line);
					if (matcherCardLinePattern.matches()) {
						Integer count = Integer.parseInt(matcherCardLinePattern.group(1));
						String name = matcherCardLinePattern.group(2);
						Card card = cardRepository.findByName(name);
						if (!isSideboard) {
							deck.addCard(card, count);
						} else {
							deck.addCardToSideboard(card, count);
						}
					} else {
						LOG.debug("Ignoring line: {}", line);
					}
				}
			} catch (Exception ex) {
				throw new RuntimeException("Error al procesar la linea '" + line + "'", ex);
			}
		}
		return deck;
	}
}
